package com.hb.trade.api.routine.controller.project.file;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.hb.core.pojo.JSONArrayProperty;
import com.hb.core.pojo.center.au.dto.OrgCollectionDTO;
import com.hb.core.pojo.center.au.dto.OrgPayeeDTO;
import com.hb.core.pojo.center.au.entity.OrgCollection;
import com.hb.core.pojo.parent.PageResult;
import com.hb.core.pojo.project.file.dto.BidFileInfoDTO;
import com.hb.core.pojo.project.file.entity.BidFileInfo;
import com.hb.core.pojo.project.section.dto.BidDownRecordDTO;
import com.hb.core.pojo.project.section.dto.BidSectionDTO;
import com.hb.core.pojo.project.section.entity.BidDownRecord;
import com.hb.trade.api.routine.service.BidFileInfoService;
import com.hb.trade.api.routine.sms.annotation.SmsSend;
import com.hb.trade.client.center.OrgClient;
import com.hb.trade.client.project.BidFileInfoClient;
import com.hb.trade.client.project.BidOpeningClient;
import com.hb.trade.client.project.ProjectClient;
import com.hb.trade.client.project.SectionClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.fzzn.core.auth.shiro.util.ShiroUtil;
import org.fzzn.core.cache.inmemory.InMemoryService;
import org.fzzn.core.file.entity.HbFileInfo;
import org.fzzn.core.file.service.DownloadService;
import org.fzzn.core.file.service.PersistenceService;
import org.fzzn.core.model.constant.CommonConstant;
import org.fzzn.core.model.enums.MsgEnum;
import org.fzzn.core.model.msg.Message;
import org.fzzn.core.model.msg.ResponseDto;
import org.fzzn.core.util.IdUtil;
import org.fzzn.core.util.ResultUtil;
import org.fzzn.core.web.anno.Version;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * describe:招标文件相关
 *
 * @author zhongdl
 * @date 2021/12/10
 */
@Slf4j
@Version(1.0)
@Api(tags = {"招标文件相关"})
@RequestMapping("/{version}")
@RestController
public class ApiBidFileInfoController {

    protected final BidFileInfoService bidFileInfoService;
    protected final BidFileInfoClient bidFileInfoClient;
    protected final BidOpeningClient bidOpeningClient;
    protected final SectionClient sectionClient;
    protected final ProjectClient projectClient;
    protected final OrgClient orgClient;
    protected final DownloadService downloadService;
    protected final PersistenceService persistenceService;
    protected final InMemoryService memoryService;

    public ApiBidFileInfoController(BidFileInfoService bidFileInfoService,
                                    BidFileInfoClient bidFileInfoClient,
                                    BidOpeningClient bidOpeningClient,
                                    SectionClient sectionClient,
                                    ProjectClient projectClient,
                                    OrgClient orgClient,
                                    DownloadService downloadService,
                                    PersistenceService persistenceService,
                                    InMemoryService memoryService) {
        this.bidFileInfoService = bidFileInfoService;
        this.bidFileInfoClient = bidFileInfoClient;
        this.bidOpeningClient = bidOpeningClient;
        this.sectionClient = sectionClient;
        this.projectClient = projectClient;
        this.orgClient = orgClient;
        this.downloadService = downloadService;
        this.persistenceService = persistenceService;
        this.memoryService = memoryService;
    }

    @ApiOperation(value = "售卖记录", notes = "售卖记录", httpMethod = "POST")
    @PostMapping("/bidBuyRecord/saleRecord")
    public ResponseDto saleRecord(@RequestBody BidSectionDTO sectionDto) {
        return ResultUtil.msg(bidFileInfoClient.saleRecord(sectionDto));
    }

    /**
     * 导出下载记录
     *
     * @param sectionDto
     * @return org.fzzn.core.model.msg.ResponseDto
     * @author tian
     * @date 2022-5-10 11:48
     */
    @ApiOperation(value = "导出下载记录", notes = "导出下载记录", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "sectionId", value = "标段id", dataTypeClass = Long.class, required = true)
    })
    @PostMapping("/bidBuyRecord/exportSaleRecord")
    public ResponseDto exportSaleRecord(@RequestBody BidSectionDTO sectionDto) {
        Long sectionId = sectionDto.getSectionId();
        if (null == sectionId) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        Message<List<JSONObject>> downloadBySectionId = bidFileInfoClient.listDownloadBySectionId(sectionDto);
        // 若查询不到数据, 则不返回
        List<JSONObject> data = downloadBySectionId.getData();
        if (CollUtil.isEmpty(data)) {
            return ResultUtil.fail("没有可导出数据");
        }

        // 保存成临时文件
        File file = new File(CommonConstant.TEMP_PATH + "/" + IdUtil.getId() + ".xlsx");
        ExcelWriter writer = ExcelUtil.getWriter(file);
        writer.addHeaderAlias("projectName", "项目名称")
                .addHeaderAlias("sectionName", "标段名称")
                .addHeaderAlias("orgName", "投标单位名称")
                .addHeaderAlias("realName", "联系人")
                .addHeaderAlias("tel", "联系电话")
                .addHeaderAlias("downTime", "购买时间");
        writer.write(data);
        writer.flush();

        String fileId = IdUtil.getIdStr();
        InMemoryService memoryService = SpringUtil.getBean(InMemoryService.class);
        memoryService.set(fileId, file.getAbsolutePath());
        return ResultUtil.msg(true, JSONUtil.createObj().set("fileId", fileId));
    }

    // *********************************************************************************
    // *                             bidFile manage start                              *
    // *********************************************************************************

    /**
     * @param bidFileInfoDTO:
     * @Description: 查询指定项目ID的招标文件列表(不带分页)
     * @Author: zhongdl
     * @Date:2022/1/17 9:09
     * @return: {@link ResponseDto }
     **/
    @ApiOperation(value = "查询指定项目ID的招标文件列表", notes = "查询指定项目ID的招标文件列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "projectId", value = "项目信息ID", dataTypeClass = Long.class),
    })
    @PostMapping("/bidFileInfo/listFilesByProjectId")
    public ResponseDto listFilesByProjectId(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        Long projectId = bidFileInfoDTO.getProjectId();
        if (projectId == null) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        Message<List<BidFileInfo>> longMessage = bidFileInfoClient.listFilesByProjectId(bidFileInfoDTO);
        return ResultUtil.msg(longMessage);
    }

    /**
     * 查询指定项目ID的招标文件列表(带分页)
     *
     * @param bidFileInfoDTO
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "查询指定项目ID的招标文件列表", notes = "查询指定项目ID的招标文件列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "projectId", value = "项目信息ID", dataTypeClass = Long.class),
    })
    @PostMapping("/bidFileInfo/pageFilesByProjectId")
    public ResponseDto pageFilesByProjectId(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        Long projectId = bidFileInfoDTO.getProjectId();
        if (projectId == null) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        Message<PageResult<BidFileInfoDTO>> longMessage = bidFileInfoClient.pageFilesByProjectId(bidFileInfoDTO);
        return ResultUtil.msg(longMessage);
    }

    /**
     * 查询指定标段ID的招标文件列表
     *
     * @param sectionDTO
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "查询指定标段ID的招标文件", notes = "查询指定标段ID的招标文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "sectionId", value = "标段ID", dataTypeClass = Long.class),
    })
    @PostMapping("/bidFileInfo/getBidFileInfoBySectionId")
    public ResponseDto getBidFileInfoBySectionId(@RequestBody BidSectionDTO sectionDTO) {
        Long sectionId = sectionDTO.getSectionId();
        if (sectionId == null) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        Message<BidFileInfoDTO> fileMsg = bidFileInfoClient.getBidFileInfoBySectionId(sectionId);
        return ResultUtil.msg(fileMsg);
    }

    /**
     * 招标文件编制, 保存招标设置的标段信息
     * 保存招标文件实际上是把招标文件中的表单字段赋值到标段信息上
     *
     * @param bidFileInfoDTO
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "保存招标文件编辑信息", notes = "保存招标文件编辑信息", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileName", value = "招标文件名称", dataTypeClass = String.class),
            @ApiImplicitParam(name = "biddingDocument", value = "招标文件附件", dataTypeClass = String.class),
            @ApiImplicitParam(name = "documentSalePrice", value = "标书售价", dataTypeClass = BigDecimal.class),
            @ApiImplicitParam(name = "collectionId", value = "收款方式ID(为空时平台收取)", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "clarificationSubmissionEndTime", value = "澄清答疑截止时间", dataTypeClass = Date.class),
            @ApiImplicitParam(name = "openBidTime", value = "开标时间", dataTypeClass = Date.class),
            @ApiImplicitParam(name = "documentSaleStartTime", value = "文件发售开始时间", dataTypeClass = Date.class),
            @ApiImplicitParam(name = "documentSaleEndTime", value = "文件发售结束时间", dataTypeClass = Date.class),
            @ApiImplicitParam(name = "bondFlag", value = "是否缴纳保证金", dataTypeClass = int.class),
            @ApiImplicitParam(name = "bondPayType", value = "保证金缴纳方式  1 银行转账 2 电子保函 3 其他", dataTypeClass = int.class),
            @ApiImplicitParam(name = "priceForm", value = "价款形式 1 金额 2 比例 3 费率", dataTypeClass = BigDecimal.class),
            @ApiImplicitParam(name = "sectionOptions.bondFlag", value = "是否缴纳保证金", dataTypeClass = BidSectionDTO.class),
            @ApiImplicitParam(name = "sectionOptions.bond", value = "保证金金额", dataTypeClass = BidSectionDTO.class),
            @ApiImplicitParam(name = "sectionOptions.bondPayType", value = "保证金缴纳方式  11 银行转账 12 电子保函 13 其他", dataTypeClass = BidSectionDTO.class),
            @ApiImplicitParam(name = "sectionOptions.priceForm", value = "价款形式 1 金额 2 比例 3 费率", dataTypeClass = BidSectionDTO.class),
            @ApiImplicitParam(name = "sectionOptions.controlPrice", value = "控制价金额", dataTypeClass = BidSectionDTO.class),
            @ApiImplicitParam(name = "simpleOrStandard", value = "简易流程还是标准流程（1，简易，2，标准）", dataTypeClass = Integer.class)
    })
    @PostMapping("/bidFileInfo/saveBidFileInfo")
    public ResponseDto saveBidFileInfo(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        String valid = bidFileInfoDTO.paramsValid();
        if (StrUtil.isNotEmpty(valid)) {
            return ResultUtil.fail(valid);
        }
        Message<BidFileInfo> fileInfoMsg = bidFileInfoClient.saveBidFileInfo(bidFileInfoDTO);
        return ResultUtil.msg(fileInfoMsg);
    }

    /**
     * 查询招标文件详情
     * 获取所有与该招标文件的标段将信息返回
     *
     * @param bidFileInfoDTO
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "查询招标文件详情", notes = "获取所有与该招标文件的标段将信息返回")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "招标文件ID", dataTypeClass = BidFileInfoDTO.class),
    })
    @PostMapping("/bidFileInfo/getBidFileInfo")
    public ResponseDto<?> bidFileInfo(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        Long fileId = bidFileInfoDTO.getId();
        if (fileId == null) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        Message<BidFileInfoDTO> fileInfoMsg = bidFileInfoClient.getBidFileInfo(fileId);
        if (fileInfoMsg.isFail()) {
            return ResultUtil.msg(fileInfoMsg);
        }

        BidFileInfoDTO data = fileInfoMsg.getData();

        // 查询招标文件的收款方信息
        JSONArray collectionIds = data.getCollectionIds();
        if (CollUtil.isNotEmpty(collectionIds)) {
            OrgCollectionDTO collectionDTO = new OrgCollectionDTO();
            boolean collectionMessageFlag = true;
            JSONArrayProperty array = new JSONArrayProperty();
            for (Object collectionIdObj : collectionIds) {
                Long collectionId = NumberUtil.parseLong(String.valueOf(collectionIdObj));
                collectionDTO.setId(collectionId);

                Message<OrgCollection> collectionMessage = orgClient.getOrgCollectionId(collectionDTO);
                OrgCollection orgCollection = collectionMessage.getData();

                if (collectionMessage.isSuccess() && collectionMessageFlag) {
                    data.setBankAccount(orgCollection.getBankAccount());
                    data.setBankAccountName(orgCollection.getBankAccountName());
                    data.setBankDeposit(orgCollection.getBankDeposit());
                    data.setPayType(orgCollection.getPayType());
                    OrgPayeeDTO orgPayeeDTO = new OrgPayeeDTO();
                    orgPayeeDTO.setId(orgCollection.getPayeeId());
                    Message<OrgPayeeDTO> orgOrgPayeeMessage = orgClient.getOrgOrgPayeeId(orgPayeeDTO);
                    if (orgOrgPayeeMessage.getData() != null && Integer.valueOf(0).equals(orgOrgPayeeMessage.getData().getDeleteFlag())) {
                        data.setPayee(orgCollection.getPayeeId());
                    }
                    data.setCurrentImgName(orgCollection.getRawFileName());
                    collectionMessageFlag = false;
                }

                if (orgCollection != null && Integer.valueOf(0).equals(orgCollection.getDeleteFlag())) {
                    array.add(orgCollection.getId());
                }
            }
            data.setCollectionIds(array);

        }

        return ResultUtil.msg(fileInfoMsg);
    }

    /**
     * 发布招标文件
     * 修改发布状态
     * (该接口会验证指定的招标文件是否满足发布的条件)
     *
     * @param bidFileInfoDTO
     * @return
     */
    @ApiOperation(value = "发布招标文件", notes = "该接口会验证指定的招标文件是否满足发布的条件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "招标文件ID", dataTypeClass = BidFileInfoDTO.class),
    })
    @SmsSend(type = 6)
    @PostMapping("/bidFileInfo/deploy")
    public ResponseDto deploy(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        Long fileId = bidFileInfoDTO.getId();
        if (fileId == null) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        Message<Boolean> deployMsg = bidFileInfoClient.deploy(fileId);
        return ResultUtil.msg(deployMsg);
    }

    /**
     * 关联标段
     *
     * @param bidFileInfoDTO
     * @return
     */
    @ApiOperation(value = "关联标段", notes = "关联标段")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "招标文件ID", dataTypeClass = BidFileInfoDTO.class),
            @ApiImplicitParam(name = "sectionIds", value = "标段ID集合", dataTypeClass = List.class)
    })
    @PostMapping("/bidFileInfo/relateSections")
    public ResponseDto relateSections(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        Long fileId = bidFileInfoDTO.getId();
        if (fileId == null) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        List<Long> sectionIds = bidFileInfoDTO.getSectionIds();
        if (CollUtil.isEmpty(sectionIds)) {
            return ResultUtil.fail("必须选择标段");
        }
        Message<Boolean> relateMsg = bidFileInfoClient.relateSections(bidFileInfoDTO);
        return ResultUtil.msg(relateMsg);
    }

    /**
     * 生成招标文件(zbwj文件)
     *
     * @param bidDownRecord
     * @return
     * @update zhaojk
     */
    @ApiOperation(value = "生成招标文件", notes = "生成招标文件(zbwj文件)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "sectionId", value = "标段id", dataTypeClass = Long.class)
    })
    @PostMapping("/bidFileInfo/generateFile")
    public ResponseDto generateFile(@RequestBody BidSectionDTO sectionDTO) {
        // 生成物理招标文件
        Message<Long> result;
        try {
            result = bidFileInfoService.generateFile(sectionDTO);
        } catch (IOException e) {
            e.printStackTrace();
            return ResultUtil.fail("下载失败");
        }

        if (result.isFail()) {
            return ResultUtil.msg(result);
        }

        Long orgId = ShiroUtil.getOrgId();
        Long bidderId = ShiroUtil.getUserId();
        Long sectionId = sectionDTO.getSectionId();
        //判断当前登录人企业是否已下载文件，如果非首次下载者不允许下载
        Message<BidDownRecord> recordInfo = sectionClient.findBidDownRecordInfoByOrgId(orgId, sectionId);
        BidDownRecord recordData = recordInfo.getData();
        if (ObjectUtils.isNotEmpty(recordData) && !bidderId.equals(recordData.getBidderId())) {
            return ResultUtil.fail("当前招标文件已被公司其他员工下载，请勿重复下载");
        }

        List<HbFileInfo> fileInfos = persistenceService.listByIds(CollUtil.list(false, result.getData()));
        if (CollUtil.isEmpty(fileInfos)) {
            return ResultUtil.fail("招标文件获取失败");
        }
        memoryService.set(String.valueOf(result.getData()), fileInfos.get(0).getFilePath(), 3600000);

        // 保存下载记录
        BidDownRecordDTO bidDownRecord = new BidDownRecordDTO();
        bidDownRecord.setBidderId(ShiroUtil.getUserId());
        bidDownRecord.setSectionId(sectionDTO.getSectionId());
        ShiroUtil.fillOwner(bidDownRecord);
        sectionClient.saveBidDownRecord(bidDownRecord);

        JSONObject fileInfoJSON = JSONUtil.parseObj(fileInfos.get(0));
        return ResultUtil.msg(true, fileInfoJSON);
    }


    /**
     * 招标文件变更流程
     *
     * @param bidFileInfoDTO
     * @return org.fzzn.core.model.msg.ResponseDto
     * @author tian
     * @date 2022-4-13 13:59
     */
    @ApiOperation(value = "招标文件变更流程", notes = "招标文件变更流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "projectId", value = "招标项目id", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "simpleOrStandard", value = "简易流程还是标准流程（1，简易，2，标准）", dataTypeClass = Integer.class),
    })
    @PostMapping("/bidFileInfo/changeProcess")
    public ResponseDto changeProcess(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        if (null == bidFileInfoDTO.getProjectId() || null == bidFileInfoDTO.getSimpleOrStandard()) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        bidFileInfoDTO.setCreateId(ShiroUtil.getUserId());
        bidFileInfoDTO.setCreateName(ShiroUtil.getUser().getFullName());
        return ResultUtil.msg(bidFileInfoClient.changeProcess(bidFileInfoDTO));
    }


    /**
     * 查询招标项目是否已创建了流程
     *
     * @param bidFileInfoDTO
     * @return org.fzzn.core.model.msg.ResponseDto
     * @author tian
     * @date 2022-4-13 13:59
     */
    @ApiOperation(value = "查询招标项目是否已创建了流程", notes = "查询招标项目是否已创建了流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "projectId", value = "招标项目id", dataTypeClass = Long.class),
    })
    @PostMapping("/bidFileInfo/selectSimpleOrStandard")
    public ResponseDto selectSimpleOrStandard(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        if (null == bidFileInfoDTO.getProjectId()) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        return ResultUtil.msg(bidFileInfoClient.selectSimpleOrStandard(bidFileInfoDTO));
    }


    /**
     * 查询招标项目是否存在已发布的招标文件
     *
     * @param bidFileInfoDTO
     * @return org.fzzn.core.model.msg.ResponseDto
     * @author tian
     * @date 2022-4-13 13:59
     */
    @ApiOperation(value = "查询招标项目是否存在已发布的招标文件", notes = "查询招标项目是否存在已发布的招标文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "projectId", value = "招标项目id", dataTypeClass = Long.class),
    })
    @PostMapping("/bidFileInfo/selectReleaseFlag")
    public ResponseDto selectReleaseFlag(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        if (null == bidFileInfoDTO.getProjectId()) {
            return ResultUtil.msg(MsgEnum.INCORRECT_PARAM);
        }
        return ResultUtil.msg(bidFileInfoClient.selectReleaseFlag(bidFileInfoDTO));
    }

    @ApiOperation(value = "根据公告查询关联已发布的招标文件", notes = "根据公告查询关联已发布的招标文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "noticeId", value = "公告id", dataTypeClass = Long.class),
    })
    @PostMapping("/bidFileInfo/findReleaseBidFileByNoticeId")
    public ResponseDto findReleaseBidFileByNoticeId(@RequestBody BidFileInfoDTO bidFileInfoDTO) {
        if (bidFileInfoDTO == null || bidFileInfoDTO.getNoticeId() == null) {
            return ResultUtil.fail("缺少必要参数");
        }
        Message<List<BidFileInfoDTO>> result = this.bidFileInfoClient.findReleaseBidFileByNoticeId(bidFileInfoDTO);
        return ResultUtil.msg(result);
    }
}
